#include <stdio.h>

/*
 * 用指针和复杂的目标地址运算来调用函数
 */

int func1()
{
    return 1;
}

int func2()
{
    return 2;
}

int func3()
{
    return 3;
}

void main()
{
    int x;
    long a[3] = {(long)func1, (long)(func2), (long)func3};
    int (*f)();

    for (x = 0; x < 3; x++) {
        f = (int (*)())a[x];
        f();
    }
}

#if 0

/* 
 * intel 
 */
0000000000001149 <func1>:
    1149:	f3 0f 1e fa          	endbr64 
    114d:	55                   	push   %rbp		// rsp=rsp-8, (rsp)=rbp ===> subq $8,%rsp, movq %rbp,(%rsp)
    114e:	48 89 e5             	mov    %rsp,%rbp	// rbp = rsp
    1151:	b8 01 00 00 00       	mov    $0x1,%eax	// return 1
    1156:	5d                   	pop    %rbp			// rbp=(rsp), rsp+8 ===> movq (%rsp),%rbp, addq $8, %rsp
    1157:	c3                   	retq				// ===> pop %rip

0000000000001158 <func2>:
    1158:	f3 0f 1e fa          	endbr64 
    115c:	55                   	push   %rbp
    115d:	48 89 e5             	mov    %rsp,%rbp
    1160:	b8 02 00 00 00       	mov    $0x2,%eax	// return 2
    1165:	5d                   	pop    %rbp
    1166:	c3                   	retq   

0000000000001167 <func3>:
    1167:	f3 0f 1e fa          	endbr64 
    116b:	55                   	push   %rbp
    116c:	48 89 e5             	mov    %rsp,%rbp
    116f:	b8 03 00 00 00       	mov    $0x3,%eax	// return 3
    1174:	5d                   	pop    %rbp
    1175:	c3                   	retq   

0000000000001176 <main>:
    1176:	f3 0f 1e fa          	endbr64 
    117a:	55                   	push   %rbp		// rsp=rsp-8, (rsp)=rbp ===> subq $8,%rsp, movq %rbp,(%rsp)
    117b:	48 89 e5             	mov    %rsp,%rbp	// rbp = rsp
    117e:	48 83 ec 30          	sub    $0x30,%rsp	// rsp = rsp-0x30
    1182:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax	# 把fs的偏移值x28放入rax
															# 指向特定于线程或定义的结构
															# %fs:0x28主要是用来起sentinel(哨兵)的作用，
    1189:	00 00 
    118b:	48 89 45 f8          	mov    %rax,-0x8(%rbp)	# 防止overflow的，即使用了8字节进行安全保护
    118f:	31 c0                	xor    %eax,%eax		# eax 清零
    1191:	48 8d 05 b1 ff ff ff 	lea    -0x4f(%rip),%rax        # 1149 <func1>	1198 - 0x4f = 1149
    1198:	48 89 45 e0          	mov    %rax,-0x20(%rbp)			// rbp-0x20 = func1
    119c:	48 8d 05 b5 ff ff ff 	lea    -0x4b(%rip),%rax        # 1158 <func2>	11a3 - 0x4b = 1158
    11a3:	48 89 45 e8          	mov    %rax,-0x18(%rbp)			// rbp-0x18 = func2
    11a7:	48 8d 05 b9 ff ff ff 	lea    -0x47(%rip),%rax        # 1167 <func3>	11ae - 0x47 = 1167
    11ae:	48 89 45 f0          	mov    %rax,-0x10(%rbp)			// rbp-0x10 = func3

    11b2:	c7 45 d4 00 00 00 00 	movl   $0x0,-0x2c(%rbp)			// rbp-0x2c = 0
    11b9:	eb 1d                	jmp    11d8 <main+0x62>			// jump
    11bb:	8b 45 d4             	mov    -0x2c(%rbp),%eax			// eax = rbp-0x2c (0, 1, 2)
    11be:	48 98                	cltq							// rax <--- eax
    11c0:	48 8b 44 c5 e0       	mov    -0x20(%rbp,%rax,8),%rax	// rax = (rbp + [0|1|2] * 8) - 0x20 = [rpb-0x20, rpb-0x18, rbp-0x10]
    11c5:	48 89 45 d8          	mov    %rax,-0x28(%rbp)			// rbp-0x28 = rax = function
    11c9:	48 8b 55 d8          	mov    -0x28(%rbp),%rdx			// rdx = rbp-0x28 = function
    11cd:	b8 00 00 00 00       	mov    $0x0,%eax				// exa = 0
    11d2:	ff d2                	callq  *%rdx					// function()
    11d4:	83 45 d4 01          	addl   $0x1,-0x2c(%rbp)		// rbp-0x2c =+ 1
    11d8:	83 7d d4 02          	cmpl   $0x2,-0x2c(%rbp)		// 0x2 - (rbp-0x2c)
    11dc:	7e dd                	jle    11bb <main+0x45>		// <=
    11de:	90                   	nop
    11df:	48 8b 45 f8          	mov    -0x8(%rbp),%rax		// 防止overflow
    11e3:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax		// fs:0x28 = 0
    11ea:	00 00 
    11ec:	74 05                	je     11f3 <main+0x7d>		// 上面xor指令结果为零，执行正常退出，否则溢出检测失败报错
    11ee:	e8 5d fe ff ff       	callq  1050 <__stack_chk_fail@plt> // 溢出检测
    11f3:	c9                   	leaveq						// ===> mov %rbp,%rsp, pop %rbp
    11f4:	c3                   	retq						// ===> pop %rip
    11f5:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)	// 用于填补func之间的空白功能和main保持位元组对齐的功能
    11fc:	00 00 00 
    11ff:	90                   	nop

/* 
 * armv8 
 */
000000000040051c <func1>:
  40051c:	52800020 	mov	w0, #0x1                   	// #1
  400520:	d65f03c0 	ret

0000000000400524 <func2>:
  400524:	52800040 	mov	w0, #0x2                   	// #2
  400528:	d65f03c0 	ret

000000000040052c <func3>:
  40052c:	52800060 	mov	w0, #0x3                   	// #3
  400530:	d65f03c0 	ret

0000000000400534 <main>:
  400534:	a9bc7bfd 	stp	x29, x30, [sp, #-64]!	// sp = sp-64, sp=fp=x29, sp+8=lr=x30
  400538:	910003fd 	mov	x29, sp					// fp = sp
  40053c:	90000000 	adrp	x0, 400000 <_init-0x3b0>	// x0 = 400000
  400540:	91196000 	add	x0, x0, #0x658			// x0 = 400658
  400544:	910063a2 	add	x2, x29, #0x18			// x2 = x29(fp)+0x18
  400548:	aa0003e3 	mov	x3, x0					// x3 = 400658
  40054c:	a9400460 	ldp	x0, x1, [x3]			// x0 = x3[400658], x1 = x3+8[400658+8]
  400550:	a9000440 	stp	x0, x1, [x2]			// [x29(fp)+0x18] = x0 = [400658], [x29(fp)+0x18+8] = x1 = [400658+8]
  400554:	f9400860 	ldr	x0, [x3, #16]			// x0 = [x3+16] = [400658+16]
  400558:	f9000840 	str	x0, [x2, #16]			// x2+16 = [x29(fp)+0x18+16] = x0 = [400658+16] 
  40055c:	b9003fbf 	str	wzr, [x29, #60]			// x29+60 = 0
  400560:	1400000b 	b	40058c <main+0x58>
  400564:	b9803fa0 	ldrsw	x0, [x29, #60]		// x0 = x29+60
  400568:	d37df000 	lsl	x0, x0, #3				// [0, 8, 16]
  40056c:	910063a1 	add	x1, x29, #0x18			// x1 = x29(fp)+0x18
  400570:	f8606820 	ldr	x0, [x1, x0]			// x0 = (x29(fp)+0x18) + (0|8|16)
  400574:	f9001ba0 	str	x0, [x29, #48]			// save x0
  400578:	f9401ba0 	ldr	x0, [x29, #48]			// read x0
  40057c:	d63f0000 	blr	x0						// function()
  400580:	b9403fa0 	ldr	w0, [x29, #60]			// w0 = x29+60
  400584:	11000400 	add	w0, w0, #0x1			// w0 = 1, 2
  400588:	b9003fa0 	str	w0, [x29, #60]			// save w0
  40058c:	b9403fa0 	ldr	w0, [x29, #60]			// read w0
  400590:	7100081f 	cmp	w0, #0x2				// 0,1,2
  400594:	54fffe8d 	b.le	400564 <main+0x30>	// <=
  400598:	d503201f 	nop
  40059c:	a8c47bfd 	ldp	x29, x30, [sp], #64		// fp=x29 = sp, lr=x30 = sp + 8, sp = sp+64
  4005a0:	d65f03c0 	ret
  4005a4:	00000000 	.inst	0x00000000 ; undefined

/* 
 * armv7 
 */
 00010460 <func1>:
   10460:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   10464:	e28db000 	add	fp, sp, #0
   10468:	e3a03001 	mov	r3, #1
   1046c:	e1a00003 	mov	r0, r3
   10470:	e24bd000 	sub	sp, fp, #0
   10474:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
   10478:	e12fff1e 	bx	lr

0001047c <func2>:
   1047c:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   10480:	e28db000 	add	fp, sp, #0
   10484:	e3a03002 	mov	r3, #2
   10488:	e1a00003 	mov	r0, r3
   1048c:	e24bd000 	sub	sp, fp, #0
   10490:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
   10494:	e12fff1e 	bx	lr

00010498 <func3>:
   10498:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   1049c:	e28db000 	add	fp, sp, #0
   104a0:	e3a03003 	mov	r3, #3
   104a4:	e1a00003 	mov	r0, r3
   104a8:	e24bd000 	sub	sp, fp, #0
   104ac:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
   104b0:	e12fff1e 	bx	lr

000104b4 <main>:
   104b4:	e92d4800 	push	{fp, lr}
   104b8:	e28db004 	add	fp, sp, #4
   104bc:	e24dd018 	sub	sp, sp, #24
    int x;
    long a[3] = {(long)func1, (long)(func2), (long)func3};
   104c0:	e59f2054 	ldr	r2, [pc, #84]	; 1051c <main+0x68>			r2 = pc+84 = variable = 10530
   104c4:	e24b3018 	sub	r3, fp, #24			; r3 = fp-24
   104c8:	e8920007 	ldm	r2, {r0, r1, r2} ; memory ---> register		r0=r2=10530, r1=r2+4=10534, r2=r2+8=10538
   104cc:	e8830007 	stm	r3, {r0, r1, r2} ; register ---> memory		(fp-24)=r0=10530, (fp-20)=r1=10534, (fp-16)=r2=10538
    int (*f)();

    for (x = 0; x < 3; x++) {
   104d0:	e3a03000 	mov	r3, #0           ; x = 0
   104d4:	e50b3008 	str	r3, [fp, #-8]    ; save x
   104d8:	ea00000a 	b	10508 <main+0x54>
        f = (int (*)())a[x];
   104dc:	e51b3008 	ldr	r3, [fp, #-8]   ; x
   104e0:	e1a03103 	lsl	r3, r3, #2      ; r3 = x << 2 , [0, 4, 8]
   104e4:	e24b2004 	sub	r2, fp, #4      ; r2 = fp - 4
   104e8:	e0823003 	add	r3, r2, r3      ; r3 = r2 + r3 [0|4|8] --> (fp-4)+[0|4|8]
   104ec:	e5133014 	ldr	r3, [r3, #-20]	; 0xffffffec	r3 = 0:[(fp-4)-20], 1:[(fp-4)+4-20], 2:[(fp-4)+8-20]
   104f0:	e50b300c 	str	r3, [fp, #-12]  ; save function address, 0:r3=(fp-24), 1:r3=(fp-20), 2:r3=(fp-16)
        f();
   104f4:	e51b300c 	ldr	r3, [fp, #-12] ; load function address
   104f8:	e12fff33 	blx	r3             ; execl
{
    int x;
    long a[3] = {(long)func1, (long)(func2), (long)func3};
    int (*f)();

    for (x = 0; x < 3; x++) {
   104fc:	e51b3008 	ldr	r3, [fp, #-8]		; r3 = x
   10500:	e2833001 	add	r3, r3, #1			; r3 = x + 1
   10504:	e50b3008 	str	r3, [fp, #-8]		; fp-8 = x
   10508:	e51b3008 	ldr	r3, [fp, #-8]		; r3 = x
   1050c:	e3530002 	cmp	r3, #2				; 0, 1, 2
   10510:	dafffff1 	ble	104dc <main+0x28>	; <=
        f = (int (*)())a[x];
        f();
    }
}
   10514:	e24bd004 	sub	sp, fp, #4
   10518:	e8bd8800 	pop	{fp, pc}
   1051c:	00010530 	.word	0x00010530

#endif

